package dto

import (
	"strings"
	"time"

	"code.bydev.io/cht/customer/kyc_admin_service/internal/pkg/kycprovider/util"
	jsoniter "github.com/json-iterator/go"
)

type AccountWeb struct {
	SuccessURL string `json:"successUrl,omitempty"`
	ErrorURL   string `json:"errorUrl,omitempty"`
	Locale     string `json:"locale,omitempty"`
	Href       string `json:"href,omitempty"`
}

type Country struct {
	PredefinedType string   `json:"predefinedType,omitempty"`
	Values         []string `json:"values,omitempty"`
}

type CredentialType struct {
	PredefinedType string   `json:"predefinedType,omitempty"` // DEFINED(default: end user is not able to change country)    RECOMMENDED(country is preselected, end user is still able to change it)
	Values         []string `json:"values,omitempty"`
}

type WorkflowDetailsCredentialsParts struct {
	Classifier string `json:"classifier,omitempty"`
	Href       string `json:"href,omitempty"`
}

type AccountCredentials struct {
	Category           string                             `json:"category,omitempty"`
	Country            *Country                           `json:"country,omitempty"`
	CredentialType     *CredentialType                    `json:"type,omitempty"` // 同上
	ID                 string                             `json:"id,omitempty"`   // UUID of the credentials
	AllowedChannels    []string                           `json:"allowedChannels,omitempty"`
	AccountResponseAPI *AccountResponseAPI                `json:"api,omitempty"`
	Parts              *[]WorkflowDetailsCredentialsParts `json:"parts,omitempty"`
}

type WorkflowDefinition struct {
	Key         WorkflowDefinitionKeys `json:"key,omitempty"`
	Credentials []AccountCredentials   `json:"credentials,omitempty"`
}

// AccountRequest --> AccountCreation Request
type AccountRequest struct {
	CustomerInternalReference string              `json:"customerInternalReference,omitempty"`
	WorkflowDefinition        *WorkflowDefinition `json:"workflowDefinition,omitempty"`
	UserReference             string              `json:"userReference,omitempty"`
	ReportingCriteria         string              `json:"reportingCriteria,omitempty"`
	CallbackURL               string              `json:"callbackUrl,omitempty"`
	TokenLifetime             string              `json:"tokenLifetime,omitempty"`
	AccountWeb                *AccountWeb         `json:"web,omitempty"`
}

type Account struct {
	ID   string `json:"id,omitempty"` // UUID of the account
	Href string `json:"href,omitempty"`
}

type AccountResponseSDK struct {
	Token string `json:"token,omitempty"`
}

type WorkflowExecution struct {
	ID                        string                `json:"id,omitempty"` // UUID of the workflow
	AccountCredentials        []*AccountCredentials `json:"credentials,omitempty"`
	Href                      string                `json:"href,omitempty"`
	DefinitionKey             string                `json:"definitionKey,omitempty"`
	Status                    string                `json:"status,omitempty"`
	UserReference             string                `json:"userReference,omitempty"`
	CustomerInternalReference string                `json:"customerInternalReference,omitempty"`
}

type AccountResponseAPIParts struct {
	FRONT   string `json:"front,omitempty"`
	BACK    string `json:"back,omitempty"`
	FACE    string `json:"face,omitempty"`
	FACEMAP string `json:"facemap,omitempty"`
}

type AccountResponseAPI struct {
	Token                   string                   `json:"token,omitempty"`
	AccountResponseAPIParts *AccountResponseAPIParts `json:"parts,omitempty"`
	WorkflowExecution       string                   `json:"workflowExecution,omitempty"`
}

// AccountResponse --> AccountCreation Response
type AccountResponse struct {
	WorkflowResponseHeader
	Timestamp          string              `json:"timestamp,omitempty"`
	Account            *Account            `json:"account,omitempty"`
	AccountResponseSDK *AccountResponseSDK `json:"sdk,omitempty"`
	WorkflowExecution  *WorkflowExecution  `json:"workflowExecution,omitempty"`
	AccountWeb         *AccountWeb         `json:"web,omitempty"`
}

// WorkflowStatusResponse --> GetWorkflowStatus Response
type WorkflowStatusResponse struct {
	WorkflowResponseHeader
	Account           *Account           `json:"account,omitempty"`
	WorkflowExecution *WorkflowExecution `json:"workflowExecution,omitempty"`
}

// WorkflowDetailsResponse --> GetWorkflowStatus Response
type WorkflowDetailsResponse struct {
	WorkflowResponseHeader
	CreatedAt         string                `json:"createdAt,omitempty"`
	StartedAt         string                `json:"startedAt,omitempty"`
	CompletedAt       string                `json:"completedAt,omitempty"`
	Account           *Account              `json:"account,omitempty"`
	WorkflowExecution *WorkflowExecution    `json:"workflow,omitempty"`
	Credentials       []*AccountCredentials `json:"credentials,omitempty"`
	Capabilities      Capabilities          `json:"capabilities,omitempty"`
	PostProcessResult
}

type PostProcessResult struct {
	FinalResult  ReviewResult `json:"finalResult"`
	RejectLabels []string     `json:"rejectLabels"`
}

type FaceSearchFindings struct {
	Status   string   `json:"status,omitempty"`
	Findings []string `json:"findings,omitempty"`
}

type Data struct {
	CredentialType     CredentialType     `json:"type,omitempty"`
	Similarity         string             `json:"similarity,omitempty"`
	FaceSearchFindings FaceSearchFindings `json:"faceSearchFindings,omitempty"`
}
type ExtractionDataType struct {
}
type ExtractionData struct {
	Type              JUMIODocumentType `json:"type,omitempty"`
	SubType           string            `json:"subType,omitempty"`
	IssuingCountry    string            `json:"issuingCountry,omitempty"`
	FirstName         string            `json:"firstName,omitempty"`
	LastName          string            `json:"lastName,omitempty"`
	DateOfBirth       string            `json:"dateOfBirth,omitempty"`
	ExpiryDate        string            `json:"expiryDate,omitempty"`
	IssuingDate       string            `json:"issuingDate,omitempty"`
	DocumentNumber    string            `json:"documentNumber,omitempty"`
	State             string            `json:"state,omitempty"`
	PersonalNumber    string            `json:"personalNumber,omitempty"`
	OptionalMrzField1 string            `json:"optionalMrzField1,omitempty"`
	OptionalMrzField2 string            `json:"optionalMrzField2,omitempty"`
	Address           Address           `json:"address,omitempty"`
	IssuingAuthority  string            `json:"issuingAuthority,omitempty"`
	IssuingPlace      string            `json:"issuingPlace,omitempty"`
	Curp              string            `json:"curp,omitempty"`
	Gender            string            `json:"gender,omitempty"`
	Nationality       string            `json:"nationality,omitempty"`
	PlaceOfBirth      string            `json:"placeOfBirth,omitempty"`

	TaxNumber                    string `json:"taxNumber,omitempty"`
	Cpf                          string `json:"cpf,omitempty"`
	RegistrationNumber           string `json:"registrationNumber,omitempty"`
	MothersName                  string `json:"mothersName,omitempty"`
	FathersName                  string `json:"fathersName,omitempty"`
	PersonalIdentificationNumber string `json:"personalIdentificationNumber,omitempty"`
	RgNumber                     string `json:"rgNumber,omitempty"`
	DlCategories                 string `json:"dlCategories,omitempty"`
	VoterIDNumber                string `json:"voterIdNumber,omitempty"`
	IssuingNumber                string `json:"issuingNumber,omitempty"`
	PassportNumber               string `json:"passportNumber,omitempty"`
	DurationOfStay               string `json:"durationOfStay,omitempty"`
	NumberOfEntries              string `json:"numberOfEntries,omitempty"`
	VisaCategory                 string `json:"visaCategory,omitempty"`
	Dni                          string `json:"dni,omitempty"`
	Pesel                        string `json:"pesel,omitempty"`
}

type Extraction struct {
	ID          string         `json:"id,omitempty"`
	Credentials []Credentials  `json:"credentials,omitempty"`
	Decision    Decision       `json:"decision,omitempty"`
	Data        ExtractionData `json:"data,omitempty"`
}

type CapabilitiesAuthentication struct {
	ID                            string        `json:"id,omitempty"`
	Credentials                   []Credentials `json:"credentials,omitempty"`
	Decision                      Decision      `json:"decision,omitempty"`
	Data                          Data          `json:"data,omitempty"`
	ValidFaceMapForAuthentication string        `json:"validFaceMapForAuthentication,omitempty"`
}

type Similarity struct {
	ID          string        `json:"id,omitempty"`
	Credentials []Credentials `json:"credentials,omitempty"`
	Decision    Decision      `json:"decision,omitempty"`
	Data        Data          `json:"data,omitempty"`
}
type LivenessData struct {
	Type string `json:"type,omitempty"`
}
type Liveness struct {
	ID                            string        `json:"id,omitempty"`
	Credentials                   []Credentials `json:"credentials,omitempty"`
	Decision                      Decision      `json:"decision,omitempty"`
	Data                          LivenessData  `json:"data,omitempty"`
	ValidFaceMapForAuthentication string        `json:"validFaceMapForAuthentication,omitempty"`
}
type DataChecks struct {
	ID          string        `json:"id,omitempty"`
	Credentials []Credentials `json:"credentials,omitempty"`
	Decision    Decision      `json:"decision,omitempty"`
}

type AddressValidation struct {
	ID          string        `json:"id,omitempty"`
	Credentials []Credentials `json:"credentials,omitempty"`
	Decision    Decision      `json:"decision,omitempty"`
}

type ProofOfResidency struct {
	ID          string        `json:"id,omitempty"`
	Credentials []Credentials `json:"credentials,omitempty"`
	Decision    Decision      `json:"decision,omitempty"`
}

type DrivingLicenseVerification struct {
	ID          string        `json:"id,omitempty"`
	Credentials []Credentials `json:"credentials,omitempty"`
	Decision    Decision      `json:"decision,omitempty"`
}

type WatchlistScreening struct {
	ID          string                  `json:"id,omitempty"`
	Credentials []Credentials           `json:"credentials,omitempty"`
	Decision    Decision                `json:"decision,omitempty"`
	Data        *WatchlistScreeningData `json:"data,omitempty"`
}

type WatchlistScreeningData struct {
	SearchDate      string `json:"searchDate,omitempty"`
	SearchStatus    string `json:"searchStatus,omitempty"`
	SearchID        string `json:"searchId,omitempty"`
	SearchReference string `json:"searchReference,omitempty"`
	SearchResultURL string `json:"searchResultUrl,omitempty"`
	SearchResults   string `json:"searchResults,omitempty"`
}

type ImageChecks struct {
	ID          string        `json:"id,omitempty"`
	Credentials []Credentials `json:"credentials,omitempty"`
	Decision    Decision      `json:"decision,omitempty"`
	Data        Data          `json:"data,omitempty"`
}
type Details struct {
	Label string `json:"label,omitempty"`
}
type Decision struct {
	Type    string  `json:"type,omitempty"`
	Details Details `json:"details,omitempty"`
}

type Credentials struct {
	ID       string `json:"id,omitempty"`
	Category string `json:"category,omitempty"`
}

type Usability struct {
	ID          string         `json:"id,omitempty"`
	Credentials []*Credentials `json:"credentials,omitempty"`
	Decision    Decision       `json:"decision,omitempty"`
}
type Capabilities struct {
	Usability      []*Usability                  `json:"usability,omitempty"`
	Liveness       []*Liveness                   `json:"liveness,omitempty"`
	Similarity     []*Similarity                 `json:"similarity,omitempty"`
	Authentication []*CapabilitiesAuthentication `json:"authentication,omitempty"`

	ImageChecks []*ImageChecks `json:"imageChecks,omitempty"`
	Extraction  []*Extraction  `json:"extraction,omitempty"`
	DataChecks  []*DataChecks  `json:"dataChecks,omitempty"`

	WatchlistScreening         []*WatchlistScreening         `json:"watchlistScreening,omitempty"`
	AddressValidation          []*AddressValidation          `json:"addressValidation,omitempty"`
	ProofOfResidency           []*ProofOfResidency           `json:"proofOfResidency,omitempty"`
	DrivingLicenseVerification []*DrivingLicenseVerification `json:"drivingLicenseVerification,omitempty"`
}

type IDVDetail struct {
	Timestamp     string                `json:"timestamp"`
	ScanReference string                `json:"scanReference"`
	Document      IDVDetailDocument     `json:"document"`
	Transaction   IDVDetailTransaction  `json:"transaction"`
	Verification  IDVDetailVerification `json:"verification"`
	Facemap       IDVDetailFacemap      `json:"facemap"`
}

type IDVDetailDocument struct {
	Type                         string  `json:"type"`
	Dob                          string  `json:"dob"`
	Expiry                       string  `json:"expiry"`
	FirstName                    string  `json:"firstName"`
	IssuingCountry               string  `json:"issuingCountry"`
	IssuingDate                  string  `json:"issuingDate"`
	LastName                     string  `json:"lastName"`
	Number                       string  `json:"number"`
	Status                       string  `json:"status"`
	IDSubtype                    string  `json:"idSubtype"`
	Document                     string  `json:"document"`
	UsState                      string  `json:"usState"`
	PersonalNumber               string  `json:"personalNumber"`
	OptionalData1                string  `json:"optionalData1"`
	OptionalData2                string  `json:"optionalData2"`
	Address                      Address `json:"address"`
	IssuingAuthority             string  `json:"issuingAuthority"`
	IssuingPlace                 string  `json:"issuingPlace"`
	Curp                         string  `json:"curp"`
	Gender                       string  `json:"gender"`
	Nationality                  string  `json:"nationality"`
	PlaceOfBirth                 string  `json:"placeOfBirth"`
	TaxNumber                    string  `json:"taxNumber"`
	Cpf                          string  `json:"cpf"`
	RegistrationNumber           string  `json:"registrationNumber"`
	MothersName                  string  `json:"mothersName"`
	FathersName                  string  `json:"fathersName"`
	PersonalIdentificationNumber string  `json:"personalIdentificationNumber"`
	RgNumber                     string  `json:"rgNumber"`
	VoterIDNumber                string  `json:"voterIdNumber"`
	IssuingNumber                string  `json:"issuingNumber"`
}
type Address struct {
	Line1            string `json:"line1,omitempty"`
	Line2            string `json:"line2,omitempty"`
	Line3            string `json:"line3,omitempty"`
	Line4            string `json:"line4,omitempty"`
	Line5            string `json:"line5,omitempty"`
	Country          string `json:"country,omitempty"`
	PostalCode       string `json:"postalCode,omitempty"`
	Subdivision      string `json:"subdivision,omitempty"`
	City             string `json:"city,omitempty"`
	FormattedAddress string `json:"formattedAddress,omitempty"`
}
type IDVDetailTransaction struct {
	ClientIP                  string `json:"clientIp"`
	CustomerID                string `json:"customerId"`
	Date                      string `json:"date"`
	MerchantScanReference     string `json:"merchantScanReference"`
	MerchantReportingCriteria string `json:"merchantReportingCriteria"`
	Source                    string `json:"source"`
	Status                    string `json:"status"`
	UpdatedAt                 string `json:"updatedAt"`
}
type IDVDetailVerification struct {
	MrzCheck     string `json:"mrzCheck"`
	RejectReason string `json:"rejectReason"`
}
type IDVDetailFacemap struct {
}

type WorkflowDefinitionCallback struct {
	ID            string `json:"id"`
	Href          string `json:"href"`
	DefinitionKey string `json:"definitionKey"`
	Status        string `json:"status"`
}
type CallBackParameters struct {
	CallbackSentAt    string                     `json:"callbackSentAt"`
	UserReference     string                     `json:"userReference"`
	WorkflowExecution WorkflowDefinitionCallback `json:"workflowExecution"`
	Account           Account                    `json:"account"`
}

type CallBackForDVTransaction struct {
	ClientIP                  string `json:"clientIp"`
	CustomerID                string `json:"customerId"`
	Date                      string `json:"date"`
	MerchantScanReference     string `json:"merchantScanReference"`
	MerchantReportingCriteria string `json:"merchantReportingCriteria"`
	Source                    string `json:"source"`
	Status                    string `json:"status"`
	UpdatedAt                 string `json:"updatedAt"`
}

type CallBackForDVDocumentExtractedAddress struct {
	Line1            string `json:"line1,omitempty"`
	Line2            string `json:"line2,omitempty"`
	Line3            string `json:"line3,omitempty"`
	Line4            string `json:"line4,omitempty"`
	Line5            string `json:"line5,omitempty"`
	Country          string `json:"country,omitempty"`
	PostalCode       string `json:"postalCode,omitempty"`
	Subdivision      string `json:"subdivision,omitempty"`
	City             string `json:"city,omitempty"`
	FormattedAddress string `json:"formattedAddress,omitempty"`
}
type CallBackForDVDocumentExtracted struct {
	FirstName          string                                `json:"firstName"`
	LastName           string                                `json:"lastName"`
	Name               string                                `json:"name"`
	AccountNumber      string                                `json:"accountNumber"`
	Pan                string                                `json:"pan"`
	IssueDate          string                                `json:"issueDate"`
	ExpiryDate         string                                `json:"expiryDate"`
	Ssn                string                                `json:"ssn"`
	SignatureAvailable bool                                  `json:"signatureAvailable"`
	SwiftCode          string                                `json:"swiftCode"`
	Address            CallBackForDVDocumentExtractedAddress `json:"address"`
}
type CallBackForDVDocument struct {
	Type               string                         `json:"type"`    // 必须
	Country            string                         `json:"country"` // 必须
	Status             string                         `json:"status"`  // 必须
	Images             []string                       `json:"images"`  // 必须
	OriginalDocument   string                         `json:"originalDocument,omitempty"`
	CustomDocumentCode string                         `json:"customDocumentCode,omitempty"`
	ExtractedData      CallBackForDVDocumentExtracted `json:"extractedData,omitempty"`
}

type CallBackForDV struct {
	ScanReference string                   `json:"scanReference"`
	Timestamp     string                   `json:"timestamp"`
	Transaction   CallBackForDVTransaction `json:"transaction"`
	Document      CallBackForDVDocument    `json:"document"`
}
type Type struct {
	PredefinedType string `json:"predefinedType"`
	Country        string `json:"country"`
	Type           string `json:"type"`
}
type AcquisitionsResp struct {
	ScanReference     string `json:"scanReference"`
	ClientRedirectURL string `json:"clientRedirectUrl"`
}

type WorkflowResponseHeader struct {
	Type     string `json:"type"`
	Title    string `json:"title"`
	Status   string `json:"status"`
	Detail   string `json:"detail"`
	Instance string `json:"instance"`
}

type DocumentVerificationResponseHeader struct {
	Message    string `json:"message"`
	HTTPStatus int    `json:"httpStatus"`
	RequestURI string `json:"requestURI"`
}

// DocumentAcquisitionsRequest 非必填数据必须要带上omitempty, 否则会传递默认值导致对方认为传参不合法而报错！
type DocumentAcquisitionsRequest struct {
	Type                       string `json:"type"`                  // 必须
	Country                    string `json:"country"`               // 必须
	MerchantScanReference      string `json:"merchantScanReference"` // 必须
	CustomerID                 string `json:"customerId"`            // 必须
	MerchantReportingCriteria  string `json:"merchantReportingCriteria,omitempty"`
	SuccessURL                 string `json:"successUrl,omitempty"`
	ErrorURL                   string `json:"errorUrl,omitempty"`
	CallbackURL                string `json:"callbackUrl,omitempty"`
	EnableExtraction           string `json:"enableExtraction,omitempty"`
	AuthorizationTokenLifetime string `json:"authorizationTokenLifetime,omitempty"`
	BaseColor                  string `json:"baseColor,omitempty"`
	BgColor                    string `json:"bgColor,omitempty"`
	HeaderImageURL             string `json:"headerImageUrl,omitempty"`
	CustomDocumentCode         string `json:"customDocumentCode,omitempty"`
	Locale                     string `json:"locale,omitempty"`
}

type DocumentAcquisitionsResponse struct {
	DocumentVerificationResponseHeader
	ScanReference     string `json:"scanReference"`
	ClientRedirectURL string `json:"clientRedirectUrl"`
	Timestamp         string `json:"timestamp,omitempty"`
}

type InterferenceData struct {
	ReviewResult ReviewResult `json:"reviewResult"`
	CanRetry     bool         `json:"canRetry"`
	Labels       []string     `json:"labels"`
}

type NestedExtractedData struct {
	AddressFormat    string `json:"addressFormat"`
	Line1            string `json:"line1"`
	Line2            string `json:"line2"`
	Line3            string `json:"line3"`
	Line4            string `json:"line4"`
	Line5            string `json:"line5"`
	CountryCode      string `json:"countryCode"`
	PostalCode       string `json:"postalCode"`
	City             string `json:"city"`
	Subdivision      string `json:"subdivision"`
	FirstName        string `json:"firstName"`
	LastName         string `json:"lastName"`
	Ssn              string `json:"ssn"`
	SignaturePresent string `json:"signaturePresent"`
	AccountNumber    string `json:"accountNumber"`
	SwiftCode        string `json:"swiftCode"`
	IssueDate        string `json:"issueDate"`
	ExpiryDate       string `json:"expiryDate"`
	Pan              string `json:"pan"`
}

type GetDocumentDetailResponse struct {
	DocumentVerificationResponseHeader
	ScanReference string    `json:"scanReference"`
	Timestamp     time.Time `json:"timestamp"`
	Document      struct {
		Status        string `json:"status"`
		Type          string `json:"type"`
		ExtractedData struct {
			FirstName           string `json:"firstName"`
			LastName            string `json:"lastName"`
			Ssn                 string `json:"ssn"`
			SignatureAvailable  bool   `json:"signatureAvailable"`
			NestedExtractedData string `json:"extractedData"`
		} `json:"extractedData"`
		Country          string `json:"country"`
		OriginalDocument string `json:"originalDocument"`
	} `json:"document"`
	Transaction struct {
		Status                string `json:"status"`
		MerchantScanReference string `json:"merchantScanReference"`
		CustomerID            string `json:"customerId"`
		Source                string `json:"source"`
		ClientIP              string `json:"clientIp"`
	} `json:"transaction"`
	InterferenceData InterferenceData `json:"interferenceData"`
}

type GetDocumentStatusResponse struct {
	DocumentVerificationResponseHeader
	ScanReference string    `json:"scanReference"`
	Timestamp     time.Time `json:"timestamp"`
	Status        string    `json:"status"`
}

type GetDocumentImagesResponse struct {
	DocumentVerificationResponseHeader
	Timestamp time.Time `json:"timestamp"`
	Images    []struct {
		Classifier int    `json:"classifier"`
		Href       string `json:"href"`
	} `json:"images"`
	ScanReference string `json:"scanReference"`
}

func (r *WorkflowDetailsResponse) GetCountry() string {

	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return ""
	}
	extractionData := r.Capabilities.Extraction[extractionCount-1]
	return extractionData.Data.IssuingCountry
}

func (r *WorkflowDetailsResponse) GetApplicantData() *Applicant {
	identities := []*Identify{}

	for _, tmpData := range r.Capabilities.Extraction {
		appType := DocumentTypeUnknown
		switch tmpData.Data.Type {
		case JUMIODocumentTypePassport:
			appType = DocumentTypePassport
		case JUMIODocumentTypeDriver:
			appType = DocumentTypeDriver
		case JUMIODocumentTypeID:
			appType = DocumentTypeID
		case JUMIODocumentTypeVISA:
			appType = DocumentTypeBank
		}

		identify := &Identify{
			Type:       appType,
			Country:    tmpData.Data.IssuingCountry,
			Firstname:  tmpData.Data.FirstName,
			Lastname:   tmpData.Data.LastName,
			Validuntil: tmpData.Data.ExpiryDate,
			Dob:        tmpData.Data.DateOfBirth,
			Number:     tmpData.Data.DocumentNumber,
		}
		identities = append(identities, identify)
	}
	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return nil
	}
	extractionData := r.Capabilities.Extraction[extractionCount-1]
	appData := &Applicant{
		ID:         extractionData.Data.DocumentNumber,
		Country:    extractionData.Data.IssuingCountry,
		Firstname:  extractionData.Data.FirstName,
		Lastname:   extractionData.Data.LastName,
		Dob:        extractionData.Data.DateOfBirth,
		Gender:     extractionData.Data.Gender,
		Identities: identities,
		PassTime:   r.CompletedAt,
	}
	return appData
}
func (r *WorkflowDetailsResponse) GetReviewLabel() []string {
	if r.FinalResult == ReviewResultReject && len(r.RejectLabels) > 0 {
		return r.RejectLabels
	}

	mapLabels := make(map[string]string)

	if r.Capabilities.Usability != nil {
		for _, a := range r.Capabilities.Usability {
			if a.Decision.Type != "PASSED" {
				mapLabels[a.Decision.Details.Label] = a.Decision.Details.Label
			}
		}
	}
	if r.Capabilities.ImageChecks != nil {
		for _, a := range r.Capabilities.ImageChecks {
			if a.Decision.Type != "PASSED" {
				mapLabels[a.Decision.Details.Label] = a.Decision.Details.Label
			}
		}
	}

	if r.Capabilities.DataChecks != nil {
		for _, a := range r.Capabilities.DataChecks {
			if a.Decision.Type != "PASSED" {
				mapLabels[a.Decision.Details.Label] = a.Decision.Details.Label
			}
		}
	}

	if r.Capabilities.Liveness != nil {
		for _, a := range r.Capabilities.Liveness {
			if a.Decision.Type != "PASSED" {
				mapLabels[a.Decision.Details.Label] = a.Decision.Details.Label
			}
		}
	}

	if r.Capabilities.Similarity != nil {
		for _, a := range r.Capabilities.Similarity {
			if a.Decision.Type != "PASSED" {
				mapLabels[a.Decision.Details.Label] = a.Decision.Details.Label
			}
		}
	}

	if r.Capabilities.Extraction != nil {
		for _, a := range r.Capabilities.Extraction {
			// 判断年龄是否大于18岁
			if a.Decision.Type == "PASSED" {
				if isGreater18, err := util.JudgeAgeIsGreaterThan18ByStrDateOfBirth(a.Data.DateOfBirth); err != nil || !isGreater18 {
					mapLabels[a.Decision.Details.Label] = "IS_GREATER_18"
				}
			} else {
				mapLabels[a.Decision.Details.Label] = a.Decision.Details.Label
			}
		}
	}
	labels := make([]string, 0)
	for _, val := range mapLabels {
		labels = append(labels, val)

	}
	return labels
}

func (r *WorkflowDetailsResponse) GetReviewLabelStr() string {
	lbls := r.GetReviewLabel()
	if len(lbls) < 1 {
		return ""
	}
	return strings.Join(lbls, ",")
}

func (r *WorkflowDetailsResponse) CanRetry() bool {
	if r.WorkflowExecution == nil {
		return true
	}
	switch r.WorkflowExecution.Status {
	case "INITIATED":
		return false
	case "ACQUIRED":
		return false
	case "PROCESSED":
		break
	case "SESSION_EXPIRED":
		return true
	case "TOKEN_EXPIRED":
		return true
	default:
		return true
	}
	labels := r.GetReviewLabel()
	mapRetryLabels := map[string]int{
		"AGE_DIFFERENCE":                 0,
		"DIGITAL_COPY":                   0,
		"DIGITAL_MANIPULATION":           0,
		"FRAUDSTER":                      0,
		"FAKE":                           0,
		"GHOST_IMAGE_DIFFERENT":          0,
		"ID_USED_AS_SELFIE":              0,
		"MANIPULATED":                    0,
		"MANIPULATED_DOCUMENT":           0,
		"MISMATCHING_DATA_REPEATED_FACE": 0,
		"MISMATCHING_DATAPOINTS":         0,
		"NFC_CERTIFICATE":                0,
		"MULTIPLE_PEOPLE":                0,
		"OTHER_REJECTION":                0,
		"PHOTOCOPY":                      0,
		"PUNCHED":                        0,
	}
	bRetry := true
	for _, label := range labels {
		if _, ok := mapRetryLabels[label]; ok {
			bRetry = false
		}
	}
	return bRetry

}
func (r *WorkflowDetailsResponse) GetState() VerificationState {
	if r.WorkflowExecution == nil {
		return VerificationStateInit
	}
	switch r.WorkflowExecution.Status {
	case "INITIATED":
		return VerificationStateInit
	case "ACQUIRED":
		return VerificationStateACQUIRED
	case "PROCESSED":
		return VerificationStatePROCESSED
	case "SESSION_EXPIRED":
		return VerificationStateSESSIONEXPIRED
	case "TOKEN_EXPIRED":
		return VerificationStatePROCESSED
	default:
		return VerificationStateTOKENEXPIRED
	}
}
func (r *WorkflowDetailsResponse) Reviewdate() string {
	return r.CompletedAt
}
func (r *WorkflowDetailsResponse) GetReviewResult() ReviewResult {
	if len(r.RejectLabels) > 0 {
		return r.FinalResult
	}

	result := ReviewResultReject
	var bUsability, bImageChecks, bDataChecks, bLiveness, bSimilarity, bExtraction bool
	var bSelfie, bFacemap, bID bool
	if r.Capabilities.Usability == nil {
		return result
	}
	for _, a := range r.Capabilities.Usability {
		if a.Decision.Type == "PASSED" {
			for _, credential := range a.Credentials {
				switch credential.Category {
				case "SELFIE":
					bSelfie = true
				case "FACEMAP":
					bFacemap = true
				case "ID":
					bID = true
				}
			}
			if bSelfie && bFacemap && bID {
				bUsability = true
			}
		}
	}
	bSelfie = false
	bID = false
	if r.Capabilities.ImageChecks == nil {
		return result
	}
	for _, a := range r.Capabilities.ImageChecks {
		if a.Decision.Type == "PASSED" {
			for _, credential := range a.Credentials {
				switch credential.Category {
				case "SELFIE":
					bSelfie = true
				case "ID":
					bID = true
				}
			}
			if bSelfie && bID {
				bImageChecks = true
			}
		}
	}
	if r.Capabilities.DataChecks == nil {
		return result
	}
	for _, a := range r.Capabilities.DataChecks {
		if a.Decision.Type == "PASSED" {
			for _, credential := range a.Credentials {
				if credential.Category == "ID" {
					bDataChecks = true
				}
			}
		}
	}

	bSelfie = false
	bFacemap = false
	if r.Capabilities.Liveness == nil {
		return result
	}
	for _, a := range r.Capabilities.Liveness {
		if a.Decision.Type == "PASSED" {
			for _, credential := range a.Credentials {
				switch credential.Category {
				case "SELFIE":
					bSelfie = true
				case "FACEMAP":
					bFacemap = true
				}
			}
			if bSelfie && bFacemap {
				bLiveness = true
			}
		}
	}
	bSelfie = false
	bID = false
	if r.Capabilities.Similarity == nil {
		return result
	}
	for _, a := range r.Capabilities.Similarity {
		if a.Decision.Type == "PASSED" {
			for _, credential := range a.Credentials {
				switch credential.Category {
				case "SELFIE":
					bSelfie = true
				case "ID":
					bID = true
				}
			}
			if bSelfie && bID {
				bSimilarity = true
			}
		}
	}
	if r.Capabilities.Extraction == nil {
		return result
	}
	for _, a := range r.Capabilities.Extraction {
		// 判断年龄是否大于18岁
		if isGreater18, err := util.JudgeAgeIsGreaterThan18ByStrDateOfBirth(a.Data.DateOfBirth); err != nil || !isGreater18 {
			return ReviewResultReject
		}
		if a.Decision.Type == "PASSED" {
			for _, credential := range a.Credentials {
				if credential.Category == "ID" {
					bExtraction = true
				}
			}
		}
	}
	if bUsability && bImageChecks && bDataChecks && bLiveness && bSimilarity && bExtraction {
		result = ReviewResultPass
	}
	return result
}

func (r *WorkflowDetailsResponse) GetNationality() string {
	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return ""
	}

	return r.Capabilities.Extraction[extractionCount-1].Data.Nationality
}

func (r *WorkflowDetailsResponse) GetDocType() string {
	for _, tmpData := range r.Capabilities.Extraction {
		if len(tmpData.Data.Type) > 0 {
			return tmpData.Data.Type.String()
		}
	}

	return JUMIODocumentTypeUNSupported.String()
}

func (r *WorkflowDetailsResponse) GetAddress() Address {
	adr := Address{
		Line1:            "",
		Line2:            "",
		Line3:            "",
		Line4:            "",
		Line5:            "",
		Country:          "",
		PostalCode:       "",
		Subdivision:      "",
		City:             "",
		FormattedAddress: "",
	}
	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return adr
	}
	adr = r.Capabilities.Extraction[extractionCount-1].Data.Address

	return adr
}

func (r *WorkflowDetailsResponse) GetAddressState() string {
	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return ""
	}

	return r.Capabilities.Extraction[extractionCount-1].Data.State
}

func (r *WorkflowDetailsResponse) GetSimilarity() string {
	sl := len(r.Capabilities.Similarity)
	if sl <= 0 {
		return ""
	}

	return r.Capabilities.Similarity[sl-1].Data.Similarity
}

func (r *WorkflowDetailsResponse) GetPersonalNumber() string {
	el := len(r.Capabilities.Extraction)
	if el <= 0 {
		return ""
	}
	return r.Capabilities.Extraction[0].Data.PersonalNumber
}

func (r *WorkflowDetailsResponse) IsValidityChecked() string {
	ll := len(r.Capabilities.Liveness)
	if ll <= 0 {
		return "false"
	}

	if r.Capabilities.Liveness[ll-1].Decision.Type == "PASSED" {
		return "true"
	}
	return "false"
}

func (r *WorkflowDetailsResponse) GetIssuingDate() string {
	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return ""
	}

	return r.Capabilities.Extraction[extractionCount-1].Data.IssuingDate
}

func (r *WorkflowDetailsResponse) GetSubType() string {
	extractionCount := len(r.Capabilities.Extraction)
	if extractionCount <= 0 {
		return ""
	}
	extractionData := r.Capabilities.Extraction[extractionCount-1]

	return extractionData.Data.SubType
}

func (r *GetDocumentDetailResponse) GetApplicantData() *Applicant {
	return nil
}
func (r *GetDocumentDetailResponse) GetCountry() string {
	return r.Document.Country
}
func (r *GetDocumentDetailResponse) GetReviewResult() ReviewResult {
	if r.InterferenceData.ReviewResult != ReviewResultUnknown {
		return r.InterferenceData.ReviewResult
	}

	if r.Document.Status == "EXTRACTED" {
		return ReviewResultPass
	}
	return ReviewResultReject
}

func (r *GetDocumentDetailResponse) CanRetry() bool {
	if r.InterferenceData.ReviewResult != ReviewResultUnknown {
		return r.InterferenceData.CanRetry
	}

	return true
}

func (r *GetDocumentDetailResponse) GetReviewLabel() []string {
	if r.InterferenceData.ReviewResult != ReviewResultUnknown {
		return r.InterferenceData.Labels
	}
	return []string{}
}

func (r *GetDocumentDetailResponse) GetReviewLabelStr() string {
	if len(r.GetReviewLabel()) < 1 {
		return ""
	}
	return strings.Join(r.GetReviewLabel(), ",")
}

func (r *GetDocumentDetailResponse) GetNestedExtractedData() *NestedExtractedData {
	nstExtraData := r.Document.ExtractedData.NestedExtractedData
	nested := new(NestedExtractedData)
	if nstExtraData == "" {
		return nested
	}
	err := jsoniter.UnmarshalFromString(nstExtraData, nested)
	if err != nil {
		return nested
	}
	return nested
}

func (r *GetDocumentDetailResponse) GetState() VerificationState {
	switch r.Transaction.Status {
	case "DONE":
		return VerificationStatePROCESSED
	case "FAILED":
		return VerificationStatePROCESSED
	}
	return VerificationStatePROCESSED
}

type SupportedDocumentTypes struct {
	Timestamp              time.Time `json:"timestamp"`
	SupportedDocumentTypes []struct {
		Code string `json:"code"`
		Name string `json:"name"`
	} `json:"supportedDocumentTypes"`
}
